package com.piece.admin.controller.system;

import com.deepoove.poi.data.Pictures;
import com.itextpdf.kernel.geom.PageSize;
import com.piece.admin.api.dto.SysUserDTO;
import com.piece.admin.api.dto.SysUserOnlineDTO;
import com.piece.admin.model.TbSysConfig;
import com.piece.admin.model.TbSysUser;
import com.piece.admin.service.TbSysConfigService;
import com.piece.admin.service.TbSysDeptService;
import com.piece.admin.service.TbSysUserService;
import com.piece.admin.support.TranslateEntity;
import com.piece.admin.support.UserInfoSupport;
import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.annotation.permission.SubmitPermission;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.exception.ServerException;
import com.piece.core.framework.support.dto.UserDetailDTO;
import com.piece.core.framework.util.time.DateUtil;
import com.piece.core.log.annotation.OperationType;
import com.piece.core.log.client.dto.UserDTO;
import com.piece.core.log.config.TenantContextHolder;
import com.piece.core.log.config.UserContextHolder;
import com.piece.core.framework.constant.ExceptionAuthConstants;
import com.piece.core.framework.support.bootstrap.DataTable;
import com.piece.core.framework.support.bootstrap.QueryTable;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.object.BeanUtil;
import com.piece.core.framework.util.object.ClassUtil;
import com.piece.core.framework.util.basic.I18nUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.framework.util.file.FileUtil;
import com.piece.core.framework.util.file.ImageUtil;
import com.piece.core.framework.util.security.SecurityUtil;
import com.piece.core.framework.util.security.coder.MD5Coder;
import com.piece.core.log.enums.AuditLogType;
import com.piece.core.web.authority.AuthorityFactory;
import com.piece.core.web.controller.FrameWorkController;
import com.piece.core.web.properties.SecurityProperties;
import com.piece.core.web.util.AuthenticationUtil;
import com.piece.file.client.FileClientFactory;
import com.piece.file.model.TbSysFile;
import com.piece.file.service.TbSysFileService;
import com.piece.module.file.util.excel.ExcelParam;
import com.piece.module.file.util.excel.ExcelUtil;
import com.piece.module.file.util.pdf.BuilderContext;
import com.piece.module.file.util.pdf.PdfUtil;
import com.piece.module.file.util.word.WordUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@Api(tags = {"用户管理"})
@RequestMapping("/api/system/user")
public class SysUserController extends FrameWorkController {

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    protected TranslateEntity translateEntity;

    @Autowired
    private SecurityProperties securityProperties;

    @Resource
    private AuthorityFactory authorityFactory;

    @Resource
    private FileClientFactory fileClientFactory;

    @Resource
    private TbSysUserService tbSysUserService;

    @Resource
    private TbSysDeptService tbSysDeptService;

    @Resource
    private TbSysConfigService tbSysConfigService;

    @Resource
    private TbSysFileService tbSysFileService;

    @PostMapping("/list")
    @AclPermission(code = "system:user:view")
    @ApiOperation(value = "查询用户列表")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    public List list() {
        QueryTable queryTable = initTable();
        Map<String, Object> params = queryTable.getParams();
        getDeptCondition(params);
        DataTable dataTable = tbSysUserService.findPage(queryTable);
        return dataTable.getData();
    }

    @PostMapping("/table")
    @AclPermission(code = "system:user:view")
    @ApiOperation(value = "查询用户分页数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name="roleId", value = "所属角色ID"),
            @ApiImplicitParam(name="roleIdNot", value = "非所属角色ID"),
            @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    })
    public AjaxResponse table() {
        QueryTable queryTable = initTable();
        Map<String, Object> params = queryTable.getParams();
        getDeptCondition(params);
        String roleId = getRequest().getParameter("roleId");
        String roleIdNot = getRequest().getParameter("roleIdNot");

        DataTable dataTable;
        if (StringUtil.isNotEmpty(roleId)) {
            dataTable = tbSysUserService.findRoleUserPage(queryTable, Convert.toLong(roleId));
        } else if (StringUtil.isNotEmpty(roleIdNot)) {
            dataTable = tbSysUserService.findNotRoleUserPage(queryTable, Convert.toLong(roleIdNot));
        } else {
            dataTable = tbSysUserService.findPage(queryTable);
        }

        return success(dataTable);
    }

    private void getDeptCondition(Map<String, Object> params) {
        Long deptId = Convert.toLong(params.get("Q_deptId_S_EQ"), null);
        if (null != deptId) {
            List<Long> deptCondition = tbSysDeptService.getDeptCondition(deptId);
            if (null != deptCondition) {
                params.remove("Q_deptId_S_EQ");
                params.put("Q_deptId_L_IN", deptCondition);
            }
        }
    }

    @GetMapping("/load")
    @ApiOperation(value = "生成用户表单数据")
    @ApiImplicitParam(name = "id", value = "主键")
    public AjaxResponse load() {
        long id = Convert.toLong(getRequest().getParameter("id"), 0L);
        TbSysUser user = new TbSysUser();
        if (id != 0) {
            user = tbSysUserService.findById(id);
            UserInfoSupport.setOtherInfo(user);
        }
        // 特殊字段重新赋值
        translateEntity.setEntityInfo(user);
        return success(user);
    }

    @GetMapping("/load/basic/{id}")
    @ApiOperation(value = "加载用户基本信息")
    @ApiImplicitParam(name = "id", value = "主键", type = "path")
    public AjaxResponse load(@PathVariable Long id) {
        TbSysUser user = tbSysUserService.findById(id);
        return success(user);
    }

    @SubmitPermission
    @PostMapping("/save")
    @AclPermission(code = "system:user:add,system:user:edit")
    @ApiOperation(value = "保存用户")
    @ApiImplicitParam(value = "表单数据", dataTypeClass = TbSysUser.class, type = "body")
    @OperationType(AuditLogType.INSERT)
    public AjaxResponse save() {
        try {
            TbSysUser user;
            Long id = Convert.toLong(getRequest().getParameter("userId"));
            if (null != id) {
                user = tbSysUserService.findById(id);
            } else {
                user = new TbSysUser();
            }

            initDB(user);

            if (ClassUtil.isEmpty(id)) {
                String name = user.getLoginName();
                String pwd = securityProperties.getToken().getPassword();
                String salt = SecurityUtil.randomSalt();
                user.setSalt(salt);
                user.setPassword(MD5Coder.decode(name + pwd + salt));
                setDefaultInfo(user, true);
                tbSysUserService.insertWithPostRole(user);
            } else {
                setDefaultInfo(user, false);
                tbSysUserService.updateWithPostRole(user);
            }
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/update")
    @AclPermission(code = "system:user:edit", checkOwner = true, param = "path")
    @ApiOperation(value = "更新用户基本信息")
    @ApiImplicitParam(value = "表单数据", dataTypeClass = TbSysUser.class, type = "body")
    @OperationType(AuditLogType.UPDATE)
    public AjaxResponse update() {
        try {
            Long id = Convert.toLong(getRequest().getParameter("userId"));
            TbSysUser temp = tbSysUserService.findById(id);
            if (null == temp) {
                throw new ServerException(I18nUtil.message(ExceptionAuthConstants.USER_DELETE));
            }

            initDB(temp);
            tbSysUserService.updateUserInfo(temp);
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/delete")
    @AclPermission(code = "system:user:delete")
    @ApiOperation(value = "删除用户")
    @ApiImplicitParam(name = "ids", value = "主键集合")
    @OperationType(AuditLogType.DELETE)
    public AjaxResponse delete() {
        String ids = getRequest().getParameter("ids");
        if (StringUtil.isNotEmpty(ids)) {
            List<TbSysUser> users = tbSysUserService.findByIds(Arrays.asList(Convert.toLongArray(ids)));
            tbSysUserService.deleteByIds(ids);
            users.stream().forEach(user -> {
                if (StringUtil.isNotEmpty(user.getAvatar())) {
                    TbSysFile file = tbSysFileService.findById(user.getAvatar());
                    if (null != file) {
                        try {
                            fileClientFactory.get().deleteFile(file);
                        } catch (Exception e) {
                            log.error("删除用户[{}]头像异常:{}", user.getLoginName(), e.getMessage());
                        }
                    }
                }
            });
        }
        return success(I18nUtil.message(ExceptionConstants.DELETE_SUCCESS), null);
    }

    @SubmitPermission
    @PostMapping("/resetPwd/{userId}")
    @AclPermission(code = "system:user:password")
    @ApiOperation(value = "重置密码")
    @ApiImplicitParam(name = "userId", value = "主键", type = "path")
    public AjaxResponse resetPwd(@PathVariable String userId) {
        try {
            TbSysUser user = tbSysUserService.findById(Convert.toLong(userId));
            if (null == user) {
                throw new ServerException(I18nUtil.message(ExceptionAuthConstants.USER_DELETE));
            }

            String password = MD5Coder.decode(user.getLoginName() + securityProperties.getToken().getPassword() + user.getSalt());
            tbSysUserService.resetPassword(user.getUserId(), password);
            return success(I18nUtil.message(ExceptionConstants.SAVE_SUCCESS), null);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.SAVE_FAILURE), e.getMessage());
        }
    }

    @SubmitPermission
    @PostMapping("/updatePwd/{userId}")
    @AclPermission(checkOwner = true, param = "path")
    @ApiOperation(value = "重置密码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "主键", type = "path"),
            @ApiImplicitParam(name = "oldPassword", value = "原密码"),
            @ApiImplicitParam(name = "newPassword", value = "新密码")
    })
    public AjaxResponse updatePwd(@PathVariable String userId) {
        TbSysUser user = tbSysUserService.findById(Convert.toLong(userId));
        if (null == user) {
            throw new ServerException(I18nUtil.message(ExceptionAuthConstants.USER_DELETE));
        }

        String oldPassword = getRequest().getParameter("oldPassword");
        String newPassword = getRequest().getParameter("newPassword");
        oldPassword = MD5Coder.decode(user.getLoginName() + oldPassword + user.getSalt());
        newPassword = MD5Coder.decode(user.getLoginName() + newPassword + user.getSalt());

        if (!oldPassword.equals(user.getPassword())) {
            throw new ServerException(I18nUtil.message(ExceptionAuthConstants.PASSWORD_NOMATCH));
        }

        tbSysUserService.resetPassword(user.getUserId(), newPassword);
        return success(user);
    }

    @SubmitPermission
    @PostMapping("/updateAvatar")
    @AclPermission(checkOwner = true, param = "userId")
    @ApiOperation(value = "更新用户头像数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户主键"),
            @ApiImplicitParam(name = "fileId", value = "原头像文件ID")
    })
    public AjaxResponse updateAvatar() throws Exception {
        long userId = Convert.toLong(getRequest().getParameter("userId"), 0L);
        String fileId = getRequest().getParameter("fileId");
        TbSysUser user = tbSysUserService.findById(userId);

        // 删除原头像
        if (StringUtil.isNotEmpty(user.getAvatar())) {
            List<TbSysFile> fileList = tbSysFileService.findByTableAndBusiness(TbSysUser.class.getSimpleName(), Convert.toStr(user.getUserId(), null));
            for (TbSysFile temp : fileList) {
                fileClientFactory.get().deleteFile(temp);
            }
        }
        user.setAvatar(fileId);
        tbSysUserService.updateUserInfo(user);
        refreshLoginInfo(user);
        if (StringUtil.isNotEmpty(fileId)) {
            TbSysFile file = tbSysFileService.findById(fileId);
            if (null != file) {
                file.setTable(TbSysUser.class.getSimpleName());
                file.setBusinessId(Convert.toStr(user.getUserId()));
                tbSysFileService.update(file);
            }
        }
        return success(user);
    }

    /**
     * 上传头像
     */
    @SubmitPermission
    @PostMapping("/uploadAvatar")
    @ApiOperation(value = "上传用户头像")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "avatar_data", value = "图片参数"),
            @ApiImplicitParam(name = "avatar_file", value = "头像文件"),
    })
    @OperationType(AuditLogType.IMPORT)
    public AjaxResponse uploadAvatar(@RequestParam("avatar_file") MultipartFile file) {
        String data = getRequest().getParameter("avatar_data");
        if (null != file) {
            try {
                // 剪切图片
                InputStream is = ImageUtil.cropImage(file.getOriginalFilename(), file.getInputStream(), data);
                // 压缩图片
                byte[] bytes = ImageUtil.scale(is, 200);
                TbSysFile tbSysFile = fileClientFactory.get().writeToStore(bytes, "avatar", file.getOriginalFilename(), file.getSize());
                return success(tbSysFile.getFileId());
            } catch (Exception e) {
                return error(I18nUtil.message(ExceptionConstants.UPLOAD_ERROR), e.getMessage());
            }
        }
        return error(I18nUtil.message(ExceptionConstants.NO_SELECT));
    }

    /**
     * 上传头像
     */
    @SubmitPermission
    @PostMapping("/uploadAvatarFinal")
    @ApiOperation(value = "上传用户头像")
    @ApiImplicitParam(name = "avatar_file", value = "上传文件")
    @OperationType(AuditLogType.IMPORT)
    public AjaxResponse uploadAvatarFinal(@RequestParam("avatar_file") MultipartFile file) {
        if (null != file) {
            try {
                // 剪切图片
                InputStream is = file.getInputStream();
                // 压缩图片
                byte[] bytes = ImageUtil.scale(is, 200);
                TbSysFile tbSysFile = fileClientFactory.get().writeToStore(bytes, "avatar", file.getOriginalFilename(), file.getSize());
                return success(tbSysFile.getFileId());
            } catch (Exception e) {
                return error(I18nUtil.message(ExceptionConstants.UPLOAD_ERROR), e.getMessage());
            }
        }
        return error(I18nUtil.message(ExceptionConstants.NO_SELECT));
    }

    @PostMapping("/addRoleTable")
    @AclPermission(code = "system:user:edit")
    @ApiOperation(value = "选择角色用户分页数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name="key", value = "非所属角色ID"),
            @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    })
    public AjaxResponse addRoleTable() {
        QueryTable queryTable = initTable();
        Map<String, Object> params = queryTable.getParams();
        getDeptCondition(params);
        queryTable.setAlias("u");
        String roleId = getRequest().getParameter("key");
        DataTable dataTable = null;
        if (StringUtil.isNotEmpty(roleId)) {
            dataTable = tbSysUserService.findNotRoleUserPage(queryTable, Convert.toLong(roleId));
        }
        return success(dataTable);
    }

    @SubmitPermission
    @PostMapping("/export")
    @AclPermission(code = "system:user:export")
    @ApiOperation(value = "导出用户文件")
    @ApiImplicitParam(value = "查询条件", dataTypeClass = QueryTable.class, type = "body")
    @OperationType(AuditLogType.EXPORT)
    public AjaxResponse export() {
        try {
            QueryTable queryTable = initTable();
            DataTable dataTable = tbSysUserService.findPage(queryTable);
            List<TbSysUser> list = dataTable.getData();
            ExcelParam param = ExcelParam.builder()
                    .sheetName("用户列表")
                    .convertType(SysUserDTO.class)
                    .data(list)
                    .build();
            InputStream is = ExcelUtil.write(param);
            String fileName = "[系统用户列表]_" + FileUtil.generateUniqFileName(getRequest()) + ".xlsx";
            String filePath = fileClientFactory.getNative().writeToLocalStore(FileUtil.toByte(is), FileUtil.getTempPath(), fileName);
            return success(filePath);
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.DOWNLOAD_ERROR), e.getMessage());
        }
    }

    @GetMapping("/userName")
    @ApiOperation(value = "获取用户名数据")
    @ApiImplicitParam(name = "ids", value = "用户ID集合")
    public AjaxResponse userName() {
        String ids = getRequest().getParameter("ids");
        String name = "";
        if (StringUtil.isNotEmpty(ids)) {
            name = tbSysUserService.convertIdToName(ids);
        }
        return success(name);
    }

    private void setDefaultInfo(TbSysUser user, boolean insert) {
        String userId = UserContextHolder.getUserId();
        if (insert) {
            user.setUserType(OptionType.GROUP.getCode());
            user.setStatus(StatusType.NORMAL.getCode());
            user.setCreateBy(userId);
            user.setCreateTime(new Date());
        }
        user.setUpdateBy(userId);
        user.setUpdateTime(new Date());
    }

    @RequestMapping(value = "/resume/{userId}")
    @ApiOperation(value = "加载用户简历")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户主键", type = "path")
    })
    public AjaxResponse loadResume(@PathVariable String userId) {
        return success(tbSysUserService.findUserResume(Convert.toLong(userId)));
    }

    @RequestMapping(value = "/resume/generate/{userId}")
    @AclPermission(checkOwner = true, param = "userId")
    @ApiOperation(value = "生成用户简历")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户主键", type = "path")
    })
    @OperationType(AuditLogType.GEN)
    public void generateResume(@PathVariable String userId) {
        OutputStream os = null;
        InputStream is = null;
        try {
            TbSysUser user = initUserResume(userId);
            os = getResponse().getOutputStream();
            String fileName = FileUtil.generateDownloadFileName(getRequest(), user.getUserName() + "的简历.docx");
            FileUtil.beforeDownload(getRequest(), getResponse(), fileName, "application/octet-stream;charset=UTF-8");

            Map<String, Object> data = new HashMap<>();
            BeanUtil.beanToMap(user, data);
            if (StringUtil.isNotEmpty(user.getAvatar())) {
                TbSysFile avatar = tbSysFileService.findById(user.getAvatar());
                if (null != avatar) {
                    data.put("avatar_img", Pictures.ofStream(fileClientFactory.get().downloadFile(avatar)).size(90, 110).create());
                }
            }
            if (null != user.getBirthday()) {
                data.put("birthday", DateUtil.formatDate(user.getBirthday(), "yyyy年MM月dd日"));
            }

            TbSysFile templateFile = tbSysFileService.findFileByTableTemplate("resume_template");
            if (templateFile != null) {
                is = fileClientFactory.get().downloadFile(templateFile);
            } else {
                is = FileUtil.readSystemFile("static/template/resume_template.docx");
            }
            WordUtil.generateByInputStream(is, data, os);
        } catch (Exception e) {
            log.error("生成用户简历失败", e);
        } finally {
            FileUtil.afterDownload(getResponse(), is, os);
        }
    }

    /**
     * 更新个人简历
     */
    @RequestMapping(value = "/resume/update")
    @AclPermission(checkOwner = true, param = "userId")
    @ApiOperation(value = "更新个人简历")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "user_id", value = "人员ID"),
            @ApiImplicitParam(name = "file_id", value = "原文件ID"),
            @ApiImplicitParam(name = "file", value = "上传文件"),
            @ApiImplicitParam(name = "path", value = "存储路径")
    })
    public AjaxResponse uploadFile(@RequestParam(value = "file", required = false) MultipartFile[] file, UserDetailDTO userDetail) {
        try {
            String userId = Convert.toStr(getRequest().getParameter("user_id"));
            String fileId = getRequest().getParameter("file_id");
            String path = getRequest().getParameter("path");

            if (null != file && file.length > 0) {
                TbSysFile tbSysFile;
                if (StringUtil.isNotEmpty(fileId)) {
                    Arrays.stream(fileId.split(FrameWorkConstants.SPLIT_PARAM)).forEach(id -> {
                        TbSysFile removeFile = tbSysFileService.findById(id);
                        if (null != removeFile) {
                            try {
                                fileClientFactory.get().deleteFile(removeFile);
                            } catch (Exception e) {
                                log.error("删除[{}]个人简历异常:{}", userId, e.getMessage());
                            }
                        }
                    });
                }
                fileId = "";
                for (int i = 0; i < file.length; i++) {
                    tbSysFile = fileClientFactory.get().store(file[i], path);
                    tbSysFile.setCreateBy(userDetail.getId());
                    tbSysFile.setTable("TbSysUser");
                    tbSysFile.setBusinessId(userId);
                    tbSysFileService.update(tbSysFile);
                    fileId += "," + tbSysFile.getFileId();
                }
                if (fileId.length() > 0) {
                    tbSysUserService.updateUserResume(Convert.toLong(userId), fileId.substring(1));
                    return success(I18nUtil.message(ExceptionConstants.UPLOAD_SUCCESS), fileId.substring(1));
                } else {
                    return success(I18nUtil.message(ExceptionConstants.UPLOAD_SUCCESS));
                }
            }
        } catch (Exception e) {
            return error(I18nUtil.message(ExceptionConstants.UPLOAD_ERROR), e.getMessage());
        }
        return error(I18nUtil.message(ExceptionConstants.UPLOAD_ERROR));
    }

    @RequestMapping(value = "/resume/print/{userId}")
    @AclPermission(code = "system:user:edit", checkOwner = true, param = "userId")
    @ApiOperation(value = "预览用户简历")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户id", paramType = "path")
    })
    @OperationType(AuditLogType.GEN)
    public void printResume(HttpServletRequest request, HttpServletResponse response, @PathVariable String userId) {
        OutputStream os = null;
        InputStream is = null;
        OutputStream coverOs = null;
        InputStream coverIs = null;

        try {
            TbSysUser user = initUserResume(userId);
            String resume_id = tbSysUserService.findUserResume(user.getUserId());
            TbSysFile resumeFile = tbSysFileService.findById(resume_id);
            is = fileClientFactory.get().downloadFile(resumeFile);

            String html = "";
            String contentType = resumeFile.getContentType();
            if ("doc".equalsIgnoreCase(contentType)) {
                html = WordUtil.docToHtml(is);
            } else {
                html = WordUtil.docxToHtml(is);
            }

            if (null != is) {
                is.close();
                is = null;
            }

            String fileName = FileUtil.generateDownloadFileName(request, user.getUserName() + "_简历.pdf");
            // 添加额外信息
            BuilderContext builderContext = new BuilderContext();
            builderContext.setWaterMark("Piece");
            builderContext.setShowHeader(true);
            builderContext.setShowFooter(true);
            builderContext.setLogoText("个人简历");
            coverOs = new ByteArrayOutputStream();
            PdfUtil.generateByHtml(html, builderContext, coverOs, new PageSize(PageSize.A4.getWidth(), PageSize.A4.getHeight()));
            coverIs = new ByteArrayInputStream(((ByteArrayOutputStream) coverOs).toByteArray());
            if (null != coverOs) {
                coverOs.close();
                coverOs = null;
            }
            // 添加盖章
            InputStream stamperInputStream = FileUtil.readSystemFile("static/image/stamper/stamper.png");
            builderContext.setStamper(FileUtil.toByte(stamperInputStream));
            TbSysConfig config = tbSysConfigService.findByConfigKey("resume_template_stamp_key");
            String stamperKey = null != config ? config.getConfigValue() : user.getUserName();
            builderContext.setStamperKey(stamperKey);
            builderContext.setStamperPage(1);

            config = tbSysConfigService.findByConfigKey("resume_template_x");
            float page_width = null != config ? Convert.toFloat(config.getConfigValue()) : PageSize.A4.getWidth();
            config = tbSysConfigService.findByConfigKey("resume_template_y");
            float page_height = null != config ? Convert.toFloat(config.getConfigValue()) : PageSize.A4.getHeight();
            builderContext.setStamperSizeX(Convert.toInt(page_width));
            builderContext.setStamperSizeY(Convert.toInt(page_height));

            coverOs = new ByteArrayOutputStream();
            PdfUtil.stamper(coverIs, builderContext, coverOs);
            if (null != coverIs) {
                coverIs.close();
                coverIs = null;
            }
            coverIs = new ByteArrayInputStream(((ByteArrayOutputStream) coverOs).toByteArray());
            if (null != coverOs) {
                coverOs.close();
                coverOs = null;
            }

            FileUtil.objectForWeb(request, response, coverIs, fileName);
        } catch (Exception e) {
            log.error("下载文件失败", e);
        } finally {
            try {
                if (null != coverIs) {
                    coverIs.close();
                    coverIs = null;
                }
                if (null != coverOs) {
                    coverOs.close();
                    coverOs = null;
                }
            } catch (IOException e) {}
        }
    }

    @PostMapping("/online")
    @AclPermission(code = "system:user:online")
    @ApiOperation(value = "查询在线用户分页数据")
    public AjaxResponse online() {
        QueryTable queryTable = initTable();
        String userName = getRequest().getParameter("Q_loginName_S_LK");
        Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientId(TenantContextHolder.getTenant());
        List<SysUserOnlineDTO> users = tokens.stream().map(token -> {
                    UserDetailDTO userDetail = AuthenticationUtil.getInstance(null).getUserDetail(token.getValue());
                    SysUserOnlineDTO online = new SysUserOnlineDTO();
                    online.setId(userDetail.getId());
                    online.setLoginName(userDetail.getUsername());
                    online.setAvatar(userDetail.getAvatar());
                    online.setDeptName(userDetail.getDeptName());
                    online.setAccessToken(token.getValue());
                    online.setRefreshToken(token.getRefreshToken().getValue());
                    online.setExpiresTime(token.getExpiration());
                    return online;
                }).filter(online -> null == userName ? true : online.getLoginName().toUpperCase().indexOf(userName.toUpperCase()) > -1)
                .skip(queryTable.getStart()).limit(queryTable.getLength()).collect(Collectors.toList());

        DataTable dataTable = new DataTable(queryTable, tokens.size());
        dataTable.setData(users);
        return success(dataTable);
    }

    @SubmitPermission
    @PostMapping("/offline")
    @AclPermission(code = "system:user:offline")
    @ApiOperation(value = "用户下线")
    @ApiImplicitParam(name = "userId", value = "主键", type = "path")
    public AjaxResponse offline(UserDetailDTO userDetail) {
        String userIds = getRequest().getParameter("ids");
        String[] ids = userIds.split(FrameWorkConstants.SPLIT_PARAM);
        TbSysUser tbSysUser = null;
        String names = "";
        for (String id : ids) {
            tbSysUser = tbSysUserService.findById(Convert.toLong(id));
            if (null != tbSysUser) {
                if (tbSysUser.getUserId().toString().equals(userDetail.getId())) {
                    return error(I18nUtil.message(ExceptionAuthConstants.OFFLINE_INVALID));
                }

                if (!authorityFactory.get().offLineUser(TenantContextHolder.getTenant(), tbSysUser.getLoginName())) {
                    return error();
                }

                names += ",[" + tbSysUser.getLoginName() + "]";
            }
        }

        return success(names);
    }

    private TbSysUser initUserResume(String id) {
        if (StringUtil.isEmpty(id)) {
            id = UserContextHolder.getUserId();
        }

        TbSysUser user = tbSysUserService.findById(Convert.toLong(id));
        translateEntity.setEntityInfo(user);
        return user;
    }

    private void refreshLoginInfo(TbSysUser user) {
        UserDetailDTO login = AuthenticationUtil.getInstance(getRequest()).getLoginUser();
        if ((user.getUserId() + "").equals(login.getId())) {
            UserContextHolder.set(new UserDTO(login.getId(), user.getUserName(), user.getAvatar(), login.permission(), login.getDeptId(), login.getDeptName()));
        }
    }
}
